#ifndef __MY_TOOL__
#define __MY_TOOL__

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctime>
#include <experimental/filesystem> //可以使用但是定位不了实现文件
#include </usr/include/jsoncpp/json/json.h>
#include <memory>
#include <sstream>
#include "bundle.h"

namespace Cloud_up
{
    namespace ef = std::experimental::filesystem;
    class Filetool
    {

    private:
        std::string _filename; // 文件名

    public:
        Filetool(const std::string &filename) : _filename(filename) {}
        ~Filetool() {}

        bool ReMove()//删除文件
        {
            if (this->Exists() == false) //判断文件是否为空
            {
                return false;
            }
            remove(_filename.c_str()); //删除该文件
            return true;
        }

        int64_t File_size() // 获取文件大小
        {
            struct stat st; // 文件信息结构体


            //int stat(const char *pathname, struct stat *buf);
            if (stat(_filename.c_str(), &st) < 0)
            {
                std::cout << "get File_size err" << std::endl;
                return -1;
            }
            return st.st_size;
        }

        time_t LastMTime() // 最后修改时间
        {
            struct stat st;
            if (stat(_filename.c_str(), &st) < 0)
            {
                std::cout << "get file LastMTime err" << std::endl;
                return -1;
            }
            return st.st_mtim.tv_sec;
        }

        time_t LastATime() // 最后访问时间
        {
            struct stat st;
            if (stat(_filename.c_str(), &st) < 0)
            {
                std::cout << "get file LastMTime err" << std::endl;
                return -1;
            }
            return st.st_atim.tv_sec;
        }

        std::string FileName() // 获取文件路径名称 /a/1.txt->1.txt
        {

            size_t pos = _filename.find_last_of('/'); //最后搜索/

            return _filename.substr(pos + 1);
        }

        // 获取pos位置的长度len的文件大小
        bool GetPosLen(std::string *body, size_t pos, size_t len)
        {
            size_t fsize = this->File_size(); // 获取_filename文件大小
            if (pos + len > fsize)//如果位置加上文件长度 > 文件大小
            {
                std::cout << "长度错误 " << std::endl;
                return false;
            }
            std::ifstream ifs; //文件流
            // std::cout << _filename.c_str() << std::endl;
            ifs.open(_filename.c_str(), std::ios::binary); //以二进制方式打开
            if (ifs.is_open() == false)
            {
                std::cout << "is_open() 打开错误" << std::endl;
                return false;
            }

            ifs.seekg(pos, std::ios::beg); // 定位绝对位置和相对位置 //设置读取位置到文件开始
            body->resize(len, '\0');       // 扩容 清空len长度
            ifs.read(&(*body)[0], len);    // 读源文件 长度为len 起始为body[0]
            if (ifs.good() == false) //是否操作成功
            {
                std::cout << "获取文件内容错误" << std::endl;
                ifs.close();
                return false;
            }
            ifs.close(); //关闭文件流
            return true;
        }

        // 读数据到body
        bool GetContent(std::string *body)
        {
            size_t fsize = this->File_size(); // 获取_filename大小
            return GetPosLen(body, 0, fsize);
        }

        // body 写到_filename  压缩内容/解压内容
        bool SetContent(const std::string &body)
        {
            std::ofstream ofs;
            ofs.open(_filename.c_str(), std::ios::binary); // 需要转char*

            if (!ofs.is_open())
            {
                std::cout << "打开文件错误" << std::endl;
                return false;
            }

            ofs.write(&body[0], body.size());//把body的文件写到body中

            if (ofs.good() == false)
            {
                std::cout << "写入文件错误" << std::endl;
                ofs.close();
                return false;
            }

            ofs.close();
            return true;
        }




        // 压缩
        bool Compress(const std::string &packname)
        {
            // 获取文件数据
            std::string body;
            if (this->GetContent(&body) == false) //获取文件到数据到body
            {
                std::cout << "Compress erron" << std::endl;
                return false;
            }
            // 压缩
            std::string packs = bundle::pack(bundle::LZIP, body); //把body压缩到packs (lzip)
            Filetool ft(packname);//创建一个文件 

            if (ft.SetContent(packs) == false) //进行接收压缩数据
            {
                std::cout << "Compress write errno" << std::endl;
                return false;
            }

            return true;
        }

        // 解压
        bool UnCompress(const std::string &filename)
        {
            // 获取文件数据
            std::string body;
            if (this->GetContent(&body) == false)//获取到数据
            {
                std::cout << "Compress erron" << std::endl;
                return false;
            }

            std::string packs = bundle::unpack(body); //解压

            Filetool ft(filename); // 建立新文件

            if (ft.SetContent(packs) == false) // 解压内容写到新文件来
            {
                std::cout << "Compress write errno" << std::endl;
                return false;
            }

            return true;
        }

        // 检查目录是否存在
        bool Exists()
        {
            return ef::exists(_filename);
        }
        // 创建目录
        bool CreateDir()
        {
            if (this->Exists() == true)
            {
                return true;
            }

            return ef::create_directories(_filename); // 存在目录返回false
        }

        // 遍历目录
        bool ScanDir(std::vector<std::string> *arry)
        {
            for (auto &p : ef::directory_iterator(_filename))//目录迭代器
            {
                if (ef::is_directory(p) == true) //判断是否是目录
                {
                    continue;
                }
                arry->push_back(ef::path(p).relative_path().string()); //path(p) 文件路径，名称
            }
            return true;
        }
    };

    class json_tool
    {
    public:
        // 序列化  json->str
        static bool Serialize(const Json::Value &val, std::string *str)
        {
            // StreamWriterBuilder:以一种人性化的方式将JSON格式的值写入流而不是字符串
            Json::StreamWriterBuilder swb;
            // StreamWriter:以JSON格式输出值
            std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
            std::stringstream os; //字节流

            if (sw->write(val, &os) != 0)//把json 以字符写到os中
            {
                std::cout << "序列化写入错误" << std::endl;
                return false;
            }

            *str = os.str(); //赋值
            return true;
        }

        // 反序列化 str->json
        static bool UnSerialize(const std::string &str, Json::Value *val)
        {
            Json::Value root;//存储解析后的JSON数据
            Json::CharReaderBuilder crb;//字符读取器
            std::unique_ptr<Json::CharReader> cr(crb.newCharReader()); //crb实例，方便管理
            std::string ss;
            bool ret = cr->parse(str.c_str(), str.c_str() + str.size(), val, &ss); //起始指针，结束指针，json格式，ss为报错信息
            if (ret == false)
            {
                std::cout << "反序列化写入错误" << std::endl;
                return false;
            }
            return true;
        }
    };

}
#endif